// MegaBitmap.cpp: implementation of the CMegaBitmap class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MegaBitmap.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMegaBitmap::CMegaBitmap():CBitmap()
{
	m_dwWidth = m_dwHeight = 0;
}

CMegaBitmap::~CMegaBitmap()
{

}

bool CMegaBitmap::LoadBitmap(LPCTSTR lpszResourceName)
{
	return LoadBitmap(MAKEINTRESOURCE(lpszResourceName));
}

bool CMegaBitmap::LoadBitmap(UINT nIDResource)
{
	if(!CBitmap::LoadBitmap(nIDResource))
		return false;

	BITMAP bmp;
	if(!GetBitmap(&bmp))
		return false;

	SetBitmapDimension(bmp.bmWidth, bmp.bmHeight);
	m_dwWidth = bmp.bmWidth;
	m_dwHeight = bmp.bmHeight;

	return true;
}

void CMegaBitmap::Draw(CDC * pDC, int x, int y)
{
	CDC MemDC;
	MemDC.CreateCompatibleDC(pDC);
	if(!MemDC.m_hDC)
		return ;
	CGdiObject * pOldBmp = MemDC.SelectObject(this);

	pDC->BitBlt(x, y, m_dwWidth, m_dwHeight, &MemDC, 0, 0, SRCCOPY);

	MemDC.SelectObject(pOldBmp);
}

void CMegaBitmap::DrawTransparent(CDC * pDC, int x, int y, COLORREF crTransparent, int xStart, int yStart)
{
	COLORREF crOldBack = pDC->SetBkColor(0x00FFFFFF);
	COLORREF crOldText = pDC->SetTextColor(0x00000000);
	CDC dcImage, dcTrans;

	// Create two memory dcs for the image and the mask
	dcImage.CreateCompatibleDC(pDC);
	dcTrans.CreateCompatibleDC(pDC);

	// Select the image into the appropriate dc
	CBitmap * pOldBitmapImage = dcImage.SelectObject(this);

	// Create the mask bitmap
	CBitmap bitmapTrans;
	bitmapTrans.CreateBitmap(m_dwWidth, m_dwHeight, 1, 1, NULL);

	// Select the mask bitmap into the appropriate dc
	CBitmap* pOldBitmapTrans = dcTrans.SelectObject(&bitmapTrans);

	// Build mask based on transparent colour
	dcImage.SetBkColor(crTransparent);
	dcTrans.BitBlt(0, 0, m_dwWidth, m_dwHeight, &dcImage, 0, 0, SRCCOPY);

	int nWidth = m_dwWidth - xStart;
	int nHeight = m_dwHeight - yStart;

	// Do the work - True Mask method - cool if not actual display
	pDC->BitBlt(x, y, nWidth, nHeight, &dcImage, xStart, yStart, SRCINVERT);
	pDC->BitBlt(x, y, nWidth, nHeight, &dcTrans, xStart, yStart, SRCAND);
	pDC->BitBlt(x, y, nWidth, nHeight, &dcImage, xStart, yStart, SRCINVERT);

	// Restore settings
	dcImage.SelectObject(pOldBitmapImage);
	dcTrans.SelectObject(pOldBitmapTrans);
	pDC->SetBkColor(crOldBack);
	pDC->SetTextColor(crOldText);
}

/*
HRGN CMegaBitmap::CreateRegion(COLORREF crTransparent)
{
	HRGN hRegion = NULL;
	
	// We create a memory context for working with the bitmap
	// The memory context is compatible with the display context (screen)
	HDC hMemDC = CreateCompatibleDC(NULL);
	
	// If no context is created, go away, too!
	if(!hMemDC) 
		return NULL;
		
	// In order to make the space for the region, we
	// create a bitmap with 32bit depth color and with the
	// size of the loaded bitmap!
	BITMAPINFOHEADER RGB32BITSBITMAPINFO=
	{ 
		sizeof(BITMAPINFOHEADER), 
		m_dwWidth, 
		m_dwHeight, 
		1,32,BI_RGB,0,0,0,0,0 
	};
	
	// Here is the pointer to the bitmap data
	VOID * pBits;
	
	// With the previous information, we create the new bitmap!
	HBITMAP hNewBitmap;
	hNewBitmap = CreateDIBSection(	hMemDC,
									(BITMAPINFO*) &RGB32BITSBITMAPINFO,
									DIB_RGB_COLORS, &pBits, NULL, 0);

	// If the creation process succeded...
	if(!hNewBitmap)
		return NULL;

	// We select the bitmap onto the created memory context
	// and then we store the previosly selected bitmap on this context!
	HBITMAP hPrevBmp = (HBITMAP) SelectObject(hMemDC, hNewBitmap);
		
	// We create another device context compatible with the first!
	HDC	hDC = CreateCompatibleDC(hMemDC);
	if(!hDC)
		return NULL;
		
	// We compute the number of bytes per row that the bitmap contains, rounding to 32 bit-multiples
	BITMAP bmNewBitmap;
	::GetObject(hNewBitmap, sizeof(bmNewBitmap), &bmNewBitmap);
				
	if(bmNewBitmap.bmWidthBytes % 4)
		bmNewBitmap.bmWidthBytes += 4 - (bmNewBitmap.bmWidthBytes % 4);
			
	// Copy of the original bitmap on the memory context!
	HBITMAP	hPrevBmpOrg = (HBITMAP) SelectObject(hDC, (HBITMAP) *this);
	BitBlt(hMemDC, 0, 0, m_dwWidth, m_dwHeight, hDC, 0, 0, SRCCOPY);

	#define NUMRECT	100			
	DWORD maxRect = NUMRECT;
			
	// We create the memory data
	HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER)+(sizeof(RECT)*maxRect));
	RGNDATA * pData = (RGNDATA*) GlobalLock(hData);
	pData->rdh.dwSize	= sizeof(RGNDATAHEADER);
	pData->rdh.iType	= RDH_RECTANGLES;
	pData->rdh.nCount	= 0;
	pData->rdh.nRgnSize = 0;
	SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);

	BYTE btTranspR = GetRValue(crTransparent);
	BYTE btTranspG = GetGValue(crTransparent);
	BYTE btTranspB = GetBValue(crTransparent);

	// Main loop
	BYTE * Pixeles = (((BYTE*)bmNewBitmap.bmBits) +(bmNewBitmap.bmHeight-1)*bmNewBitmap.bmWidthBytes);
	for(int Row = 0; Row < m_dwHeight; Row++) 
	{
		// Horizontal loop
		for(int Column = 0; Column < m_dwWidth; Column++)
		{
			int x0 = Column;
			BYTE * Pixel = (BYTE*) (Pixeles+Column*4);

			while(Column < m_dwWidth) 
			{
				BOOL bInRange=FALSE;

				BYTE b = *Pixel++;
				BYTE g = *Pixel++;
				BYTE r = *Pixel++;
				Pixel++;
				// If the color is that indicated as transparent...
				if(!(r == btTranspR && g == btTranspG && b == btTranspB))
				{
				}
				else
				{
					break;
				}

				Column++;
			} // while (Column < m_dwWidth) 		
					
			if(Column > x0) 
			{
				// If the number of rectangles is greater then NUMRECT, we claim
				// another pack of NUMRECT memory places!
				if (pData->rdh.nCount >= maxRect)
				{
					GlobalUnlock(hData);
					maxRect += NUMRECT;
					hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER)+(sizeof(RECT)*maxRect), GMEM_MOVEABLE);
					pData = (RGNDATA*) GlobalLock(hData);					
				}		
						
				RECT * pRect = (RECT*) &pData->Buffer;
				SetRect(&pRect[pData->rdh.nCount], x0+1, Row, Column, Row+1);		
								
				if(x0 < pData->rdh.rcBound.left)		pData->rdh.rcBound.left = x0-1;
				if(Row < pData->rdh.rcBound.top)		pData->rdh.rcBound.top = Row;
				if(Column > pData->rdh.rcBound.right)	pData->rdh.rcBound.right = Column;
				if(Row+1 > pData->rdh.rcBound.bottom)	pData->rdh.rcBound.bottom = Row+1;
		
				pData->rdh.nCount++;																	

				// In Win95/08 there is a limitation on the maximum number of
				// rectangles a RGN_DATA can store (aprox. 4500), so we call
				// the API for a creation and combination with the main region
				// each 2000 rectangles. This is a good optimization, because
				// instead of calling the routines for combining for each new
				// rectangle found, we call them every 2000 rectangles!!!
				if(pData->rdh.nCount == 2000)
				{						
					HRGN hNewRegion = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRect), pData);
					if (hNewRegion) 
					{
						// If the main region does already exist, we add the new one,
						if (hRegion) 
						{
							CombineRgn(hRegion,hRegion,hNewRegion,RGN_OR);									
							::DeleteObject(hNewRegion);
						} 
						// if not, we consider the new one to be the main region at first!
						else
						{
							hRegion=hNewRegion;
						}
					}
					pData->rdh.nCount = 0;
					SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
				}				
			} // if (Column > x0)
		} // for (int  Column ...)

		Pixeles -= bmNewBitmap.bmWidthBytes;
	} // for (int Row...)			

	HRGN hNewRegion = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER)+(sizeof(RECT)*maxRect), pData);

	if(hNewRegion) 
	{
		// If the main region does already exist, we add the new one,
		if(hRegion)
		{														
			CombineRgn(hRegion,hRegion,hNewRegion,RGN_OR);
			::DeleteObject(hNewRegion);
		}
		// if not, we consider the new one to be the main region at first!
		else
		{
			hRegion = hNewRegion;				
		}						
			
		// We free the allocated memory and the rest of used ressources
		GlobalFree(hData);
		SelectObject(hDC, hPrevBmpOrg);
		DeleteDC(hDC);
			
		SelectObject(hMemDC, hPrevBmp);
		DeleteDC(hMemDC);
	}

	return hRegion;
}
*/

HRGN CMegaBitmap::CreateRegion(COLORREF crTransparent)
{
	HRGN hRegion = ::CreateRectRgn(0, 0, m_dwWidth, m_dwHeight);
	
	// We create a memory context for working with the bitmap
	// The memory context is compatible with the display context (screen)
	HDC hMemDC = CreateCompatibleDC(NULL);
	
	// If no context is created, go away, too!
	if(!hMemDC) 
		return NULL;
		
	// In order to make the space for the region, we
	// create a bitmap with 32bit depth color and with the
	// size of the loaded bitmap!
	BITMAPINFOHEADER RGB32BITSBITMAPINFO=
	{ 
		sizeof(BITMAPINFOHEADER), 
		m_dwWidth, 
		m_dwHeight, 
		1,32,BI_RGB,0,0,0,0,0 
	};
	
	// Here is the pointer to the bitmap data
	VOID * pBits;
	
	// With the previous information, we create the new bitmap!
	HBITMAP hNewBitmap;
	hNewBitmap = CreateDIBSection(	hMemDC,
									(BITMAPINFO*) &RGB32BITSBITMAPINFO,
									DIB_RGB_COLORS, &pBits, NULL, 0);

	// If the creation process succeded...
	if(!hNewBitmap)
		return NULL;

	// We select the bitmap onto the created memory context
	// and then we store the previosly selected bitmap on this context!
	HBITMAP hPrevBmp = (HBITMAP) SelectObject(hMemDC, hNewBitmap);
		
	// We create another device context compatible with the first!
	HDC	hDC = CreateCompatibleDC(hMemDC);
	if(!hDC)
		return NULL;
		
	// We compute the number of bytes per row that the bitmap contains, rounding to 32 bit-multiples
	BITMAP bmNewBitmap;
	::GetObject(hNewBitmap, sizeof(bmNewBitmap), &bmNewBitmap);
				
	if(bmNewBitmap.bmWidthBytes % 4)
		bmNewBitmap.bmWidthBytes += 4 - (bmNewBitmap.bmWidthBytes % 4);
			
	// Copy of the original bitmap on the memory context!
	HBITMAP	hPrevBmpOrg = (HBITMAP) SelectObject(hDC, (HBITMAP) *this);
	BitBlt(hMemDC, 0, 0, m_dwWidth, m_dwHeight, hDC, 0, 0, SRCCOPY);

	BYTE btTranspR = GetRValue(crTransparent);
	BYTE btTranspG = GetGValue(crTransparent);
	BYTE btTranspB = GetBValue(crTransparent);

	// Main loop
	BYTE * pSrc = (((BYTE*)bmNewBitmap.bmBits) +(bmNewBitmap.bmHeight-1)*bmNewBitmap.bmWidthBytes);
	for(int row = 0; row < m_dwHeight; row++) 
	{
		BYTE * pRow = pSrc;
		for(int col = 0; col < m_dwWidth; col++)
		{
			BYTE b = *pRow++;
			BYTE g = *pRow++;
			BYTE r = *pRow++;
			pRow++;

			if(r == btTranspR && g == btTranspG && b == btTranspB)
			{
				HRGN hrgnTmp = ::CreateRectRgn(col, row, col+1, row+1);
				::CombineRgn(hRegion, hRegion, hrgnTmp, RGN_DIFF);
				::DeleteObject(hrgnTmp);
			}
		}
		pSrc -= bmNewBitmap.bmWidthBytes;
	}

	SelectObject(hDC, hPrevBmpOrg);
	DeleteDC(hDC);
		
	SelectObject(hMemDC, hPrevBmp);
	DeleteDC(hMemDC);
	::DeleteObject(hNewBitmap);

	return hRegion;
}